<template>
  <div class="ui-upload" v-if="editable">
    <el-upload
      action="#"
      :accept="accept"
      :disabled="disabled"
      :file-list="fileList"
      :multiple="multiple"
      :show-file-list="false"
      :on-change="handleUploadChange"
      :auto-upload="autoUpload"
      :limit="innerLimitCount"
      :http-request="handleHttpRequest"
      :before-upload="handleBeforeUpload"
      :on-exceed="handleUploadExceed"
      :on-success="handleUploadSuccess"
    >
      <slot :loading="loading" :disabled="disabled" />
    </el-upload>
  </div>
</template>
<script>
import ElUpload from 'element-ui/lib/upload'
import 'element-ui/lib/theme-chalk/upload.css'
import { getFileTitle, formatBytes } from './util'
import Message from '../message'

let number = Date.now()
function unique() {
  return number++
}

function formatValueToFileItem(value, autoUpload) {
  if (value) {
    if (typeof value === 'string') {
      return {
        id: unique(),
        title: getFileTitle(value),
        url: value,
        status: 'success',
        message: ''
      }
    } else if (value instanceof window.File) {
      return {
        id: unique(),
        title: value.name,
        file: value,
        url: window.URL.createObjectURL(value),
        status: autoUpload ? 'ready' : '',
        message: ''
      }
    }
  }
}

export default {
  name: 'UiUploadCore',
  components: {
    ElUpload
  },
  props: {
    value: {
      type: [String, File, Array],
      default: undefined
    },
    editable: {
      type: Boolean,
      default: true
    },
    disabled: {
      type: Boolean,
      default: false
    },
    multiple: {
      type: Boolean,
      default: false
    },
    autoUpload: {
      type: Boolean,
      default: true
    },
    uploadMethod: {
      type: Function
    },
    accept: {
      type: String,
      default: undefined
    },
    limitCount: {
      type: Number,
      default: undefined
    },
    limitSize: {
      type: Number,
      default: undefined
    }
  },
  data() {
    return {
      loading: false,
      fileList: []
    }
  },
  computed: {
    innerLimitCount () {
      if (this.multiple) {
        return this.limitCount || 9999999
      } else {
        return 1
      }
    },
    innerMultiple() {
      return this.multiple
    },
    /**
     * File | String | [File] | [String] | [String,File]
    */
    innerValue: {
      get() {
        return this.value
      },
      set(val) {
        // 非自动上传，取ready状态的值
        let nextValue = []
        if (this.autoUpload) {
          nextValue = (val || []).filter(v => v.status === 'success' && v.url).map(v => v.url)
        } else {
          nextValue = (val || []).filter(v => v.status === 'ready' && v.file).map(v => v.file)
        }
        if (!this.innerMultiple) {
          nextValue = nextValue[0]
        }
        this.$emit('input', nextValue)
      }
    },
    nextFileList() {
      // element file status ready | uploading | fail | success
      return this.fileList.map(v => {
        return {
          id: v.id || v.uid,
          title: v.title || v.name,
          file: v.raw ? v.raw : null,
          url: v.url ? v.url : v.raw ? window.URL.createObjectURL(v.raw) : null,
          status: v.status,
          message: v.message
        }
      })
    },
    innerLimitType() {
      let arr = []
      if (this.accept) {
        arr = this.accept.split(',')
      }
      return arr
    }
  },
  watch: {
    innerValue() {
      if (this.disabledSync) {
        return
      }
      this.syncFileList()
    },
    nextFileList() {
      this.$emit('file-list-change', {
        fileList: this.nextFileList
      })
    }
  },
  created() {
    this.syncFileList()
  },
  methods: {
    syncFileList() {
      let nextFileList = []
      if (this.innerMultiple) {
        if (this.innerValue) {
          if (Array.isArray(this.innerValue)) {
            nextFileList = this.innerValue.map(v => {
              return formatValueToFileItem(v)
            }).filter(v => !!v)
          } else {
            nextFileList = []
          }
        }
      } else {
        const file = formatValueToFileItem(this.innerValue)
        if (file) {
          nextFileList = [file]
        }
      }
      this.fileList = nextFileList
    },
    getFileIndex(fileId) {
      let index = -1
      this.fileList.some((v, i) => {
        if (v.uid === fileId || v.id === fileId) {
          index = i
          return true
        }
      })
      return index
    },
    removeFile(fileId) {
      const index = this.getFileIndex(fileId)
      if (index < 0) {
        return
      }
      const file = this.fileList[index]
      if (file) {
        this.disabledSync = true
        window.URL.revokeObjectURL(file.url)
        this.fileList.splice(index, 1)
        this.innerValue = this.nextFileList
        this.$nextTick(() => {
          this.disabledSync = false
        })
      }
    },
    checkLoading() {
      this.loading = !!this.fileList.find(v => v.status === 'uploading')
    },
    handleBeforeUpload(file) {
      if (this.innerLimitType.length && file && file.name) {
        const ext = file.name.substr(file.name.lastIndexOf('.')).toLowerCase()
        if (this.innerLimitType.indexOf(ext) < 0) {
          Message.error(`只允许上传${this.innerLimitType.join('、')}类型文件`)
          return false
        }
      }
      if (this.limitSize && file.size > this.limitSize) {
        Message.error(`上传文件大小不允许超过${formatBytes(this.limitSize)}`)
        return false
      }
    },
    handleUploadExceed(files, fileList) {
      Message.error(`最多允许上传${this.innerLimitCount}个文件`)
    },
    handleUploadChange(file, fileList) {
      this.disabledSync = true
      this.fileList = fileList
      this.innerValue = this.nextFileList
      this.$nextTick(() => {
        this.disabledSync = false
      })
      this.checkLoading()
    },
    handleUploadSuccess(uploadUrl, file, fileList) {
      this.disabledSync = true
      file.url = uploadUrl
      this.fileList = fileList
      this.innerValue = this.nextFileList
      this.$nextTick(() => {
        this.disabledSync = false
        this.$emit('upload-success', {
          file
        })
      })
    },
    handleHttpRequest(opts) {
      if (this.autoUpload) {
        if (this.uploadMethod) {
          this.uploadMethod({
            file: opts.file,
            onUploadProgress: (evt) => {
              opts.onProgress && opts.onProgress(evt)
              this.checkLoading()
            }
          }).then((url) => {
            if (url) {
              if (opts.onSuccess) {
                opts.onSuccess(url)
              }
            } else {
              opts.onError && opts.onError()
            }
          }, (err) => {
            opts.onError && opts.onError(err)
          }).finally(() => {
            this.checkLoading()
          })
        } else {
          throw new Error('缺少上传方法')
        }
      }
    }
  }
}
</script>
<style lang="less">
.ui-upload__control{
  margin-bottom: 8px;
}
</style>
